﻿using MatrixWebApiCore.Common;
using MatrixWebApiCore.Entity;
using MatrixWebApiCore.Entity.RequestModel;
using MatrixWebApiCore.Filter;
using Microsoft.Extensions.Caching.Memory;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace MatrixWebApiCore.HttpRequest
{
    public class WebClientData : IwebHttpClienBase
    {
        private static readonly object _lockObject = new object();

        private IMemoryCache _cache;
        public WebClientData(IMemoryCache memoryCache)
        {
            _cache = memoryCache;
        }

        /// <summary>
        /// （市场指数累计收益率）获取所有基准累计收益率走势图60
        /// </summary>
        /// <param name="token"></param>
        /// <param name="analysisId"></param>
        /// <param name="startDate"></param>
        /// <param name="endTime"></param>
        /// <returns></returns>
        public async Task<BackResult<object>> AllBenchmarkYieldRate(string token, int analysisId, string startDate, string endTime)
        {
            string cacheKey = $"AllBenchmarkYieldRate{analysisId}{startDate}{endTime}";
            object cacheObj = _cache.Get(cacheKey);
            if (cacheObj != null)
            {
                return new BackResult<object>() { Data = cacheObj };
            }
            //计算所有基准的累计收益率走势，调用重算方法
            List<object> listBenchmark = new List<object>();

            //获取所有基准
            string url = SysCoinfgData.ApiBaesURL + "/api/DropDownList/GetBenchmarkCode";
            //MessageHelper.LogInfo("1当前线程" + Thread.CurrentThread.ManagedThreadId);
            string backData = await HttpHelper.WebClientGetAsync(url, token);
            //MessageHelper.LogInfo("2当前线程" + Thread.CurrentThread.ManagedThreadId);
            List<NameValueItem> list = Newtonsoft.Json.JsonConvert.DeserializeObject<List<NameValueItem>>(backData);
            //调用重算接口
            string url_Calculate = SysCoinfgData.ApiBaesURL + "/api/PerformanceAnalysis/Calculate";
            ConcurrentBag<Task> taskList = new ConcurrentBag<Task>();
            //Stopwatch ss = new Stopwatch();
            //ss.Start();
            List<string> allowBenkList = new List<string>() { "沪深300", "上证综指", "深证成指", "上证50", "中证500", "中证800", "创业板指", "深证综指" };
            //选择上面允许的基准数据 
            list = list.AsParallel().Where(w => allowBenkList.Contains(w.Text)).ToList();
            string remoteMsg = "";
            Parallel.ForEach(list, (item, loopState) =>
            {
                taskList.Add(Task.Factory.StartNew(() =>
                {
                    try
                    {
                        //Stopwatch st = new Stopwatch();
                        //st.Start();
                        var obj = new
                        {
                            Body = new
                            {
                                AnalysisId = analysisId,//分析id
                                StartTime = startDate,
                                EndTime = endTime,
                                BenchmarkCode = item.Value, //基准
                                PerformanceType = 3 // 分析类型，0交易记录，1资金交易记录，2净值类型，3故值类型，4净值持仓
                            }
                        };
                        string backMsg = HttpHelper.WebClientPost(url_Calculate, Newtonsoft.Json.JsonConvert.SerializeObject(obj), token);
                        dynamic jsonObject = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(backMsg);
                        if (Convert.ToInt32(jsonObject.Head.Code.Value) < 400)
                        {
                            //将折线处理成 x轴:数组，y轴:数组
                            string json = Newtonsoft.Json.JsonConvert.SerializeObject(jsonObject.Result.Performance.IndexTotalProfitRatDatas);
                            List<double[]> xyArr = Newtonsoft.Json.JsonConvert.DeserializeObject<List<double[]>>(json);
                            List<double> xArr = xyArr.AsParallel().Select(w => w[0]).OrderBy(w => w).ToList();
                            //保留4位小数
                            List<double> yArr = xyArr.Select(w => w[1]).Select(w => Math.Round(w, 4)).ToList();
                            listBenchmark.Add(new { Code = item.Value, Name = item.Text, xData = xArr, yData = yArr });
                        }
                        else
                        {
                            remoteMsg = jsonObject.Head.Message.Value;
#if DEBUG
                            MessageHelper.LogErrorInfo("市场指数累计收益率60，基准" + item.Text + item.Value + "返回了异常：" + remoteMsg);
#endif
                            //loopState.Stop();
                            //return;
                        }
                        //st.Stop();
                        //MessageHelper.LogInfo(item.Value + "执行时长" + st.ElapsedMilliseconds);
                    }
                    catch (Exception ex)
                    {
#if DEBUG
                        MessageHelper.LogErrorInfo("市场指数累计收益率，异常", ex);
#endif
                        loopState.Stop();
                        return;
                    }
                }, TaskCreationOptions.LongRunning));
            });
            await Task.WhenAll(taskList.ToArray());
            //MessageHelper.LogInfo("3当前线程" + Thread.CurrentThread.ManagedThreadId);
            //ss.Stop();
            //MessageHelper.LogInfo("总执行时长" + ss.ElapsedMilliseconds);

            //if (!string.IsNullOrWhiteSpace(remoteMsg))
            //{
            //    return new BackResult<object>() { Success = false, Msg = "来自源数据消息：" + remoteMsg };
            //}
            //缓存数据      
            _cache.Set(cacheKey, listBenchmark, DateTimeOffset.Now.AddSeconds(SysCoinfgData.MemoryCacheLiveTime));
            return new BackResult<object>() { Data = listBenchmark };
        }

        /// <summary>
        /// 获取基金详细信息，有缓存
        /// </summary>
        /// <param name="token"></param>
        /// <param name="productId"></param>
        /// <returns></returns>
        public ProductDetail GetProductDetail(string token, int productId)
        {
            string cacheKey = $"GetProductDetail{productId}";
            object cacheObj = _cache.Get(cacheKey);
            if (cacheObj != null)
            {
                return cacheObj as ProductDetail;
            }
            ProductDetail model = null;
            //基金基本信息
            string json = "{\"Body\": { \"Id\": @Id} }";
            string url = SysCoinfgData.ApiBaesURL + "/api/ProductManager/Details";
            string jsonBack = "";
            try
            {
                jsonBack = HttpHelper.WebClientPost(url, json.Replace("@Id", productId.ToString()), token);
            }
            catch (Exception ex)
            {
#if DEBUG
                MessageHelper.LogErrorInfo("获取基金基本信息异常，方法GetProductDetail", ex);
#endif
                throw new OutMsgException("获取基金基本信息处理异常");
            }
            dynamic productDynamic = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(jsonBack);
            if (Convert.ToInt32(productDynamic.Head.Code.Value) > 400)
            {
#if DEBUG
                MessageHelper.LogErrorInfo("获取基金基本信息异常，方法GetProductDetail" + jsonBack);
#endif
                throw new OutMsgException("数据源消息【获取基金基本信息】：" + productDynamic.Head.Message);
            }
            string jsonResult = Newtonsoft.Json.JsonConvert.SerializeObject(productDynamic.Result);
            model = Newtonsoft.Json.JsonConvert.DeserializeObject<ProductDetail>(jsonResult);
            //缓存数据      
            _cache.Set(cacheKey, model, DateTimeOffset.Now.AddSeconds(SysCoinfgData.MemoryCacheLiveTime));
            return model;
        }

        /// <summary>
        /// 获取，基本信息10
        /// </summary>
        /// <param name="token"></param>
        /// <param name="parames"></param>
        /// <returns></returns>
        public async Task<BackResult<object>> BasicInfoAsync(string token, TargetParames parames)
        {
            string cacheKey = $"BasicInfoAsync{parames.AnalysisId}{parames.StartDate}{parames.EndDate}";
            object cacheObj = _cache.Get(cacheKey);
            if (cacheObj != null)
            {
                return new BackResult<object>() { Data = cacheObj };
            }
            string json = "{\"Body\": { \"Id\": @Id} }";
            //分析详情里面获取基金规模，最新净值，预期年收益
            string fenxiURL = SysCoinfgData.ApiBaesURL + "/api/PerformanceAnalysis/Details";
            Task<string> analysis_task = HttpHelper.WebClientPostAsync(fenxiURL, json.Replace("@Id", parames.AnalysisId.ToString()), token);
            //最新净值
            string _netValue = "";
            Task fundNetTask = Task.Run(() =>
            {
                List<double[]> fund_NetVal = FundsNetValues(token, parames.AnalysisId, parames.StartDate, parames.EndDate);
                if (fund_NetVal != null && fund_NetVal.Count > 0)
                {
                    _netValue = fund_NetVal.AsParallel().Last()[1].ToString();
                }
            });

            //基金基本信息
            ProductDetail productDetail = null;
            Task productInfo_task = Task.Run(() =>
            {
                productDetail = GetProductDetail(token, parames.ProductId);
            });
            string analysisJson = await analysis_task;
            dynamic analysis = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(analysisJson);
            if (Convert.ToInt32(analysis.Head.Code.Value) > 400)
            {
                return new BackResult<object>() { Success = false, Msg = "来自源数据消息：" + analysis.Head.Message };
            }
            //年化收益率
            //var chartsBasicData_json = Newtonsoft.Json.JsonConvert.SerializeObject(analysis.Result.CalculateResult.ChartsBasicData);
            //List<ChartsBasicData> list = Newtonsoft.Json.JsonConvert.DeserializeObject<List<ChartsBasicData>>(chartsBasicData_json);
            //预期年收益
            //double yearReturn = list.First().DynameicConditions.YearReturn;
            //基金规模
            double scale = (analysis.Result.CalculateResult.FundScaleChange.FundScaleData[analysis.Result.CalculateResult.FundScaleChange.FundScaleData.Count - 1])[1];

            await productInfo_task;
            string _shortName = productDetail.Name;
            string _invest = productDetail.InvestmentStrategyName;
            string _organization = productDetail.Organization;
            string _foundDate = "";
            if (productDetail.StartTime.HasValue)
            {
                _foundDate = productDetail.StartTime.Value.ToString("yyyy-MM-dd");
            }
            await fundNetTask;
            List<object> bkList = new List<object>();
            bkList.Add(new { Des = "基金简称", CellVal = _shortName, });
            bkList.Add(new { Des = "基金规模", CellVal = scale, });
            bkList.Add(new { Des = "投资标的", CellVal = _invest, });
            bkList.Add(new { Des = "基金公司", CellVal = _organization, });
            bkList.Add(new { Des = "成立日期", CellVal = _foundDate, });
            bkList.Add(new { Des = "最新净值", CellVal = _netValue, });
            bkList.Add(new { Des = "预期年收益", CellVal = "0.2" });
            //缓存数据      
            _cache.Set(cacheKey, bkList, DateTimeOffset.Now.AddSeconds(SysCoinfgData.MemoryCacheLiveTime));
            return new BackResult<object>() { Data = bkList };
        }

        /// <summary>
        /// 获取，风险指标数据20
        /// </summary>
        /// <param name="token"></param>
        /// <param name="parames"></param>
        /// <returns></returns>
        public async Task<BackResult<object>> RiskIndicator(string token, TargetParames parames)
        {
            string cacheKey = $"RiskIndicator{parames.AnalysisId}{parames.StartDate}{parames.EndDate}";
            object cacheObj = _cache.Get(cacheKey);
            if (cacheObj != null)
            {
                return new BackResult<object>() { Data = cacheObj };
            }
            //string json = "{\"Body\": { \"Id\": @Id} }";
            ////分析详情里面获取风险指标
            //string fenxiURL = SysCoinfgData.ApiBaesURL + "/api/PerformanceAnalysis/Details";
            //var data = await HttpHelper.WebClientPostAsync(fenxiURL, json.Replace("@Id", parames.AnalysisId.ToString()), token);
            var data = await Task.Factory.StartNew(() =>
            {
                return AnalysisCalculateCache(token, parames.AnalysisId, parames.StartDate, parames.EndDate);
            }, TaskCreationOptions.LongRunning);

            dynamic jsonObject = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(data);
            if (Convert.ToInt32(jsonObject.Head.Code.Value) > 400)
            {
                return new BackResult<object>() { Success = false, Msg = "来自源数据消息：" + jsonObject.Head.Message };
            }
            string incomeRisk_json = Newtonsoft.Json.JsonConvert.SerializeObject(jsonObject.Result.IncomeRisk);
            List<IncomeRiskOut> list = Newtonsoft.Json.JsonConvert.DeserializeObject<List<IncomeRiskOut>>(incomeRisk_json);
            IncomeRiskValue model = list.AsParallel().FirstOrDefault(w => w.Key.Contains("基金") || w.Key.Contains("Funds")).Value.AsParallel().FirstOrDefault(w => w.Key == "All").Value;

            List<object> arr = new List<object>();
            arr.Add(new { Des = "alpha", CellVal = model.Alpha });
            arr.Add(new { Des = "beta", CellVal = model.Beta });
            arr.Add(new { Des = "sharpe", CellVal = model.YearSharpRatio });
            arr.Add(new { Des = "年化波动", CellVal = model.YearWaveRatio });
            arr.Add(new { Des = "最大回撤", CellVal = model.MaxDrawDownRate });
            //缓存数据      
            _cache.Set(cacheKey, arr, DateTimeOffset.Now.AddSeconds(SysCoinfgData.MemoryCacheLiveTime));
            return new BackResult<object>() { Data = arr }; ;
        }

        /// <summary>
        /// 获取，业绩表现数据30
        /// </summary>
        /// <param name="token"></param>
        /// <param name="parames"></param>
        /// <returns></returns>
        public async Task<BackResult<object>> Performance(string token, TargetParames parames)
        {
            string cacheKey = $"Performance{parames.AnalysisId}{parames.StartDate}{parames.EndDate}";
            object cacheObj = _cache.Get(cacheKey);
            if (cacheObj != null)
            {
                return new BackResult<object>() { Data = cacheObj };
            }
            var task1 = Task.Factory.StartNew(() =>
            {
                //基准单位净值走势，要自己算，这里只算沪深300
                return UnitNetValueBenchmark(token, "000300.SH", parames.StartDate, parames.EndDate);
            }, TaskCreationOptions.LongRunning);

            //计算同类均值的单位净值走势
            var task_tonglei = Task.Factory.StartNew(() =>
            {
                return SameAvgNetVal(token, parames.ProductId, parames.StartDate, parames.EndDate);
            }, TaskCreationOptions.LongRunning);

            //基金单位净值走势
            List<double[]> fundList = FundsNetValues(token, parames.AnalysisId, parames.StartDate, parames.EndDate);
            //以基金单位净值走势日期为参照，筛选出基准的单位净值对应日期
            var fund_xData = fundList.Select(w => w[0]).ToList();

            //表格用
            List<object> incomeRateArr = new List<object>();
            //沪深300单位净值走势
            List<double[]> benchmarkUnitNetValues = await task1;
            //日期和基金日期对比，如果基金日期有的，同类均值此日期无值，则复制最近前一条记录
            List<double> benk_xTime = benchmarkUnitNetValues.AsParallel().Select(w => w[0]).ToList();
            benchmarkUnitNetValues.Capacity = benchmarkUnitNetValues.Count + 100;
            Parallel.ForEach(fund_xData, item =>
            {
                if (!benk_xTime.Contains(item))
                {
                    //查找前一条记录值
                    var findList = benchmarkUnitNetValues.AsParallel().Where(w => w[0] < item).OrderBy(w => w[0]).ToList();
                    if (findList != null && findList.Count > 0)
                    {
                        double value = findList.Last()[1];
                        benchmarkUnitNetValues.Add(new double[] { item, value });
                    }
                }
            });
            benchmarkUnitNetValues = benchmarkUnitNetValues.OrderBy(w => w[0]).ToList();

            //基金本周收益率
            double weekfundReturn = 0,
            //基金本月收益率
              fund_thisMonthReturn = 0,
            //基金本年收益率
              fundThisYearReturn = 0,
              //基金成立以来收益率
              fundNowReturn = 0;

            //基准的本周收益率
            double benkThisWeekReturn = 0,
            //基准本月收益率
              ben_thisMonthReturn = 0,
            //基准今年收益率
              benThisYearRetun = 0,
              //基准成立以来收益率
              benNowReturn = 0;

            //同类均值本周收益率
            double same_weekReturn = 0,
            //同类均值本月收益率
            same_thisMonthReturn = 0,
            //同类今年收益率
            same_thisYearReturn = 0;

            //计算基金、沪深300的收益率
            var task_incomeReturn = Task.Run(() =>
            {
                //计算基金本周收益率  
                //查找上周五的日期
                double dateCurrent = fundList.Last()[0];
                long dateStamp = Convert.ToInt64(dateCurrent / 1000);
                DateTime fund_lastDay_datetime = DateHelpter.StampToDateTime(dateStamp);
                DateTime friday = DateHelpter.GetDateLastFriday(fund_lastDay_datetime);
                double netValFriday = 0;
                //判断离周报成立日开始的天数差
                if (Math.Abs(dateStamp - fundList.First()[0] / 1000) > 518400)//判断是否大于一周
                {
                    long datefriday = DateHelpter.Stamp(friday);
                    //上周五净值
                    var fundSearchList = fundList.Where(w => w[0] / 1000 <= datefriday);
                    if (fundSearchList != null && fundSearchList.Count() > 0)
                    {
                        netValFriday = fundSearchList.Last()[1];
                    }
                }
                else
                {
                    netValFriday = fundList.First()[1];
                }
                //基金本周收益率=（本周结束日单位净值-本周起始日单位净值）/本周起始日单位净值
                weekfundReturn = fundList.Last()[1] / netValFriday - 1;
                //基金本月收益率         
                DateTime lastMonthDay = DateHelpter.GetLastMonthLastDay(fund_lastDay_datetime);
                //long lastMonthDay_long = DateHelpter.Stamp(lastMonthDay);
                if (Math.Abs(fundList.Last()[0] / 1000 - fundList.First()[0] / 1000) >= 2592000) //判断成立以来是否大于一个月
                {
                    var findList = fundList.Where(w => DateHelpter.StampToDateTime((long)w[0] / 1000).ToString("yyyy-MM") == lastMonthDay.ToString("yyyy-MM")).ToList();
                    if (findList != null && findList.Count > 0)
                    {
                        double netValLastMonthLastDay = findList.Last()[1];
                        //double netValLastMonthLastDay = fundList.Where(w => w[0] / 1000 == lastMonthDay_long).First()[1];
                        fund_thisMonthReturn = fundList.Last()[1] / netValLastMonthLastDay - 1;
                    }
                }
                else
                {
                    fund_thisMonthReturn = fundList.Last()[1] / fundList.First()[1] - 1;
                }
                //基金今年收益率          
                long firstDay_stamp = (long)fundList.First()[0] / 1000;
                DateTime firstfundsDay_datetime = DateHelpter.StampToDateTime(firstDay_stamp);
                fundThisYearReturn = 0;
                if (fund_lastDay_datetime.Year == firstfundsDay_datetime.Year)
                {
                    fundThisYearReturn = fundList.Last()[1] / fundList.First()[1] - 1;
                }
                else
                {
                    //DateTime thisYearFirstDay = Convert.ToDateTime(fund_lastDay_datetime.Year + "-01-01");
                    //long thisYearfirstDay_long = DateHelpter.Stamp(thisYearFirstDay);
                    //double thisYearfirstDay_netVal = fundList.Where(w => w[0] / 1000 == thisYearfirstDay_long).First()[1];
                    //去年最后一天的净值
                    var fundFoundArr = fundList.Where(w => DateHelpter.StampToDateTime((long)w[0] / 1000).Year == fund_lastDay_datetime.AddYears(-1).Year).ToList();
                    if (fundFoundArr != null && fundFoundArr.Count > 0)
                    {
                        double thisYearfirstDay_netVal = fundFoundArr.Last()[1];
                        fundThisYearReturn = fundList.Last()[1] / thisYearfirstDay_netVal - 1;
                    }
                }
                //基金成立以来收益率
                fundNowReturn = fundList.Last()[1] / fundList.First()[1] - 1;

                //基准的本周收益率               
                long currentDay = (long)benchmarkUnitNetValues.Last()[0] / 1000;
                DateTime currentDay_datetime = DateHelpter.StampToDateTime(currentDay);
                long bekFirstStamp = (long)benchmarkUnitNetValues.First()[0] / 1000;
                DateTime bekFirstDateTime = DateHelpter.StampToDateTime(bekFirstStamp);

                DateTime benkLastFriday = DateHelpter.GetDateLastFriday(currentDay_datetime);
                long benkFridayStamp = DateHelpter.Stamp(benkLastFriday);
                var benkWeekFound = benchmarkUnitNetValues.Where(w => w[0] / 1000 <= benkFridayStamp).ToList();
                if (benkWeekFound != null && benkWeekFound.Count > 0)
                {
                    double netValFriDay_benk = benkWeekFound.Last()[1];
                    benkThisWeekReturn = benchmarkUnitNetValues.Last()[1] / netValFriDay_benk - 1;
                }
                //基准本月收益率                
                if (currentDay_datetime.ToString("yyyy-MM") == bekFirstDateTime.ToString("yyyy-MM"))
                {
                    ben_thisMonthReturn = benchmarkUnitNetValues.Last()[1] / benchmarkUnitNetValues.First()[1] - 1;
                }
                else
                {
                    DateTime lastMonthDay_benk = DateHelpter.GetLastMonthLastDay(currentDay_datetime);
                    //上个月的最后一个的净值
                    var fundList2 = benchmarkUnitNetValues.Where(w => DateHelpter.StampToDateTime((long)w[0] / 1000).ToString("yyyy-MM") == lastMonthDay_benk.ToString("yyyy-MM")).ToList();
                    if (fundList2 != null && fundList2.Count > 0)
                    {
                        double netValMonth_benk = fundList2.Last()[1];
                        ben_thisMonthReturn = benchmarkUnitNetValues.Last()[1] / netValMonth_benk - 1;
                    }
                }
                //基准今年收益率                
                long firstDay_benk = (long)benchmarkUnitNetValues.First()[0] / 1000;
                DateTime firstDay_benk_datetime = DateHelpter.StampToDateTime(firstDay_benk);
                if (currentDay_datetime.Year == firstDay_benk_datetime.Year)
                {
                    benThisYearRetun = benchmarkUnitNetValues.Last()[1] / benchmarkUnitNetValues.First()[1] - 1;
                }
                else
                {
                    //DateTime thisYearFirstDay = Convert.ToDateTime(currentDay_datetime.Year + "-01-01");
                    //long thisYearfirstDay_long = DateHelpter.Stamp(thisYearFirstDay);
                    //去年最后一天净值
                    var benkFoundList = benchmarkUnitNetValues.Where(w => DateHelpter.StampToDateTime((long)w[0] / 1000).Year == currentDay_datetime.AddYears(-1).Year).OrderBy(w => w[0]).ToList();
                    if (benkFoundList != null && benkFoundList.Count > 0)
                    {
                        double thisYearfirstDay_netVal = benkFoundList.Last()[1];
                        benThisYearRetun = benchmarkUnitNetValues.Last()[1] / thisYearfirstDay_netVal - 1;
                    }
                }
                //基准成立以来收益率
                benNowReturn = benchmarkUnitNetValues.Last()[1] / benchmarkUnitNetValues.First()[1] - 1;
            });

            List<object> quxian = new List<object>();

            //同类均值走势
            List<KeyValuePair<long, double>> netvalueDict = await task_tonglei;
            if (netvalueDict != null && netvalueDict.Count > 0)
            {
                List<long> x_timeArr = fund_xData.ConvertAll(w => Convert.ToInt64(w));
                List<long> same_xTime = netvalueDict.AsParallel().Select(w => w.Key).ToList();
                netvalueDict.Capacity = netvalueDict.Count + 100;
                Parallel.ForEach(x_timeArr, item =>
                {
                    if (!same_xTime.Contains(item))
                    {
                        MessageHelper.LogInfo($"同类均值净值在基金{item}这天无值");
                        //查找前一条记录值
                        var fundSearchList = netvalueDict.AsParallel().Where(w => w.Key < item).OrderBy(w => w.Key);
                        if (fundSearchList != null && fundSearchList.Count() > 0)
                        {
                            double value = fundSearchList.AsParallel().Last().Value;
                            netvalueDict.Add(new KeyValuePair<long, double>(item, value));
                            MessageHelper.LogInfo($"同类均值净值补填值{item},{value}");
                        }
                    }
                });
            }
            var netvalueDictSored = netvalueDict.AsParallel().OrderBy(w => w.Key);
            //计算同类均值收益率
            Task calute_sameTask = Task.Run(() =>
            {
                //日期和基金日期对比，如果基金日期有的，同类均值此日期无值，则复制最近前一条记录
                //转换为long类型
                if (netvalueDict != null && netvalueDict.Count > 0)
                {
                    //计算同类均值本周收益率                
                    long lastday_same = netvalueDictSored.Last().Key / 1000;
                    DateTime lastDay_datetime = DateHelpter.StampToDateTime(lastday_same);
                    long firstday_same = netvalueDictSored.First().Key / 1000;
                    if ((lastday_same - firstday_same) > 518400) //判断是否大于6天
                    {
                        DateTime friday = DateHelpter.GetDateLastFriday(lastDay_datetime);
                        long friday_stamp = DateHelpter.Stamp(friday);
                        var sameSearchList = netvalueDictSored.AsParallel().Where(w => w.Key / 1000 <= friday_stamp);
                        if (sameSearchList != null && sameSearchList.Count() > 0)
                        {
                            double friday_netvalue = sameSearchList.AsParallel().Last().Value;
                            same_weekReturn = netvalueDictSored.Last().Value / friday_netvalue - 1;
                        }
                        else
                        {
                            same_weekReturn = 0;
                        }
                    }
                    else
                    {
                        same_weekReturn = netvalueDictSored.Last().Value / netvalueDictSored.First().Value - 1;
                    }
                    //同类均值本月收益率                  
                    DateTime firstDay_datetime = DateHelpter.StampToDateTime(firstday_same);
                    if ((lastDay_datetime - firstDay_datetime).TotalDays <= 30)
                    {
                        same_thisMonthReturn = netvalueDictSored.Last().Value / netvalueDictSored.First().Value - 1;
                    }
                    else
                    {
                        DateTime lastMonthLastDay_time = DateHelpter.GetLastMonthLastDay(lastDay_datetime);
                        //long lastMonthLastDay_stamp = DateHelpter.Stamp(lastMonthLastDay_time);
                        var sameFoundList = netvalueDictSored.Where(w => DateHelpter.StampToDateTime(w.Key / 1000).ToString("yyyy-MM") == lastMonthLastDay_time.ToString("yyyy-MM")).OrderBy(w => w.Key);
                        if (sameFoundList != null && sameFoundList.Count() > 0)
                        {
                            double friday_netvalue = sameFoundList.Last().Value;
                            //double friday_netvalue = netvalueDictSored.AsParallel().Where(w => w.Key / 1000 == lastMonthLastDay_stamp).First().Value;
                            same_thisMonthReturn = netvalueDictSored.Last().Value / friday_netvalue - 1;
                        }
                    }
                    //同类今年收益率                    
                    if (firstDay_datetime.Year == lastDay_datetime.Year)
                    {
                        same_thisYearReturn = netvalueDictSored.Last().Value / netvalueDictSored.First().Value - 1;
                    }
                    else
                    {
                        //查找去年最后一天       
                        var sameSearchList = netvalueDictSored.Where(w => DateHelpter.StampToDateTime(w.Key / 1000).Year == lastDay_datetime.AddYears(-1).Year);
                        if (sameSearchList != null && sameSearchList.Count() > 0)
                        {
                            double firstDay_netvalue = sameSearchList.Last().Value;
                            same_thisYearReturn = netvalueDictSored.Last().Value / firstDay_netvalue - 1;
                        }
                    }
                }
            });

            //----基金净值走势-----
            //小数处理
            var fund_yData = fundList.Select(w => w[1]).ToList();
            fund_yData = fund_yData.Select(w => Math.Round(w, 4)).ToList();
            quxian.Add(new
            {
                Key = "FundNetValue",
                Title = "基金",
                xData = fund_xData,
                yData = fund_yData
            });

            //-------同类均值净值走势------
            //List<long> xData_sameAvgValue = netvalueDictSored.AsParallel().Select(w => w.Key).OrderBy(w => w).ToList();
            List<double> yData_sameAvgValue = netvalueDictSored.AsParallel().Where(w => fund_xData.Contains(w.Key)).OrderBy(w => w.Key).Select(w => w.Value).ToList();
            yData_sameAvgValue = yData_sameAvgValue.Select(w => Math.Round(w, 4)).ToList();
            quxian.Add(new
            {
                Key = "SameAvgValue",
                Title = "同类均值",
                //Msg = sameAvgNetValErrorMsg,
                xData = fund_xData,
                yData = yData_sameAvgValue
            });

            //------日期符合基金日期的，基准单位净值集合-----         
            var benk_yData = benchmarkUnitNetValues.Where(w => fund_xData.Contains(w[0])).Select(w => w[1]).ToList();
            //小数处理
            benk_yData = benk_yData.Select(w => Math.Round(w, 4)).ToList();
            quxian.Add(new
            {
                Key = "BenkNetValue",
                Title = "沪深300",
                xData = fund_xData,
                yData = benk_yData
            });

            //等待收益率计算完成
            await task_incomeReturn;
            List<object> arr_funds = new List<object>();
            arr_funds.Add(new { Des = "名称", CellVal = "基金" });
            arr_funds.Add(new { Des = "本周", CellVal = weekfundReturn });
            arr_funds.Add(new { Des = "本月", CellVal = fund_thisMonthReturn });
            arr_funds.Add(new { Des = "今年同期", CellVal = fundThisYearReturn });
            arr_funds.Add(new { Des = "成立以来", CellVal = fundNowReturn });
            incomeRateArr.Add(arr_funds);

            //等待同类均值收益率计算完成
            await calute_sameTask;
            List<object> same_arr = new List<object>();
            same_arr.Add(new { Des = "名称", CellVal = "同类均值" });
            if (yData_sameAvgValue.Count == 0)
            {
                same_arr.Add(new { Des = "本周", CellVal = "--" });
                same_arr.Add(new { Des = "本月", CellVal = "--" });
                same_arr.Add(new { Des = "今年同期", CellVal = "--" });
            }
            else
            {
                same_arr.Add(new { Des = "本周", CellVal = same_weekReturn });
                same_arr.Add(new { Des = "本月", CellVal = same_thisMonthReturn });
                same_arr.Add(new { Des = "今年同期", CellVal = same_thisYearReturn });
            }
            same_arr.Add(new { Des = "成立以来", CellVal = "--" });
            incomeRateArr.Add(same_arr);

            List<object> arr_hs = new List<object>();
            arr_hs.Add(new { Des = "名称", CellVal = "沪深300" });
            arr_hs.Add(new { Des = "本周", CellVal = benkThisWeekReturn });
            arr_hs.Add(new { Des = "本月", CellVal = ben_thisMonthReturn });
            arr_hs.Add(new { Des = "今年同期", CellVal = benThisYearRetun });
            arr_hs.Add(new { Des = "成立以来", CellVal = "--" });
            incomeRateArr.Add(arr_hs);

            var backObj = new
            {
                Graph = quxian,  //曲线图净值走势
                Table = incomeRateArr  //表格收益率
            };
            //缓存数据      
            _cache.Set(cacheKey, backObj, DateTimeOffset.Now.AddSeconds(SysCoinfgData.MemoryCacheLiveTime));
            return new BackResult<object>() { Data = backObj };
        }

        /// <summary>
        /// 获取基金单位净值走势
        /// </summary>
        /// <param name="token"></param>
        /// <param name="analysisId"></param>
        /// <param name="startDate"></param>
        /// <param name="endDate"></param>
        /// <returns></returns>
        public List<double[]> FundsNetValues(string token, int analysisId, string startDate, string endDate)
        {
            string cacheKey = $"FundsNetValues{analysisId}{startDate}{endDate}";
            object cacheObj = _cache.Get(cacheKey);
            if (cacheObj != null)
            {
                return cacheObj as List<double[]>;
            }
            string json = AnalysisCalculateCache(token, analysisId, startDate, endDate);
            dynamic jsonObject = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(json);
            //基金单位净值走势
            string json_NetValue = Newtonsoft.Json.JsonConvert.SerializeObject(jsonObject.Result.Performance.ProductUnitNetValueDatas);
            List<double[]> fundList = Newtonsoft.Json.JsonConvert.DeserializeObject<List<double[]>>(json_NetValue);
            //处理特殊情况
            //找出周五的记录
            List<double[]> fridayList = fundList.AsParallel().Where(w => DateHelpter.StampToDateTime((long)w[0] / 1000).DayOfWeek == DayOfWeek.Friday).OrderBy(w => w[0]).ToList();
            if (fridayList != null && fridayList.Count > 0)
            {
                //判断两个记录之间的日期天数差
                double[] lastObj = fridayList[0];
                for (int i = 1; i < fridayList.Count; i++)
                {
                    var item = fridayList[i];
                    int cha = (int)(item[0] / 1000 - lastObj[0] / 1000) / (3600 * 24);//转换为差多少天
                    if (cha > 7)
                    {
                        //表示此范围有周五没有数据，找出此天，然后填充值
                        DateTime addFridayItem = DateHelpter.StampToDateTime((long)lastObj[0] / 1000).AddDays(7);
                        double date = DateHelpter.Stamp(addFridayItem) * 1000;
                        //查找前最近一天的净值
                        var searchList = fundList.AsParallel().Where(w => w[0] < date).OrderBy(w => w[0]);
                        if (searchList != null && searchList.Count() > 0)
                        {
                            double netVal = searchList.Last()[1];
                            fundList.Add(new double[] { date, netVal });
                        }
                    }
                    lastObj = item;
                }
            }
            fundList = fundList.OrderBy(w => w[0]).ToList();
            //缓存数据      
            _cache.Set(cacheKey, fundList, DateTimeOffset.Now.AddSeconds(SysCoinfgData.MemoryCacheLiveTime));
            return fundList;
        }

        /// <summary>
        /// 获取同类均值净值走势，有缓存
        /// </summary>
        /// <param name="token"></param>
        /// <param name="productId"></param>
        /// <param name="startDate"></param>
        /// <param name="endDate"></param>
        /// <returns></returns>
        public List<KeyValuePair<long, double>> SameAvgNetVal(string token, int productId, string startDate, string endDate)
        {
            string cacheKey = $"SameAvgNetVal{productId}{startDate}{endDate}";
            object cacheObj = _cache.Get(cacheKey);
            if (cacheObj != null)
            {
                return cacheObj as List<KeyValuePair<long, double>>;
            }
            //返回集合
            List<KeyValuePair<long, double>> newList = new List<KeyValuePair<long, double>>();
            //装基金的累计单位净值集合
            List<FundQuote> fundQuoteList = new List<FundQuote>(20000);
            //同类均值（同类平均净值），long为时间戳，double为净值
            ConcurrentDictionary<long, double> netvalueDict = new ConcurrentDictionary<long, double>();
            //lock (_lockObject)
            //{
            //获取日期列表
            List<DateTime?> dateList = null;

            var baseUrl = SysCoinfgData.QuotesAPI + "/api/FundHistoryQuotes?";
            //将22个分成10组，同时并发请求结果
            //000844.OF,000762.OF,519062.OF,001791.OF,000753.OF,002527.OF,000754.OF,001641.OF,001792.OF,000585.OF,002655.OF,001059.OF,000992.OF,000414.OF,002804.OF,001073.OF,001896.OF,000667.OF,000672.OF,002224.OF,001565.OF,005280.OF
            ConcurrentBag<string> list = new ConcurrentBag<string>() { "000844.OF,000762.OF", "519062.OF,001791.OF", "000753.OF,002527.OF", "000754.OF,001641.OF", "001792.OF,000585.OF", "002655.OF,001059.OF", "000992.OF,000414.OF", "002804.OF,001073.OF", "001896.OF,000667.OF", "000672.OF,002224.OF", "001565.OF,005280.OF" };

            //.OF基金基本信息，获取基金开始日期，此集合装.OF基金在（周报基金成立日）那天的净值，方便后面计算【.OF基金当天累计收益率】
            ConcurrentDictionary<string, double> dict = new ConcurrentDictionary<string, double>();
            ProductDetail productDetail = GetProductDetail(token, productId);
            string _startDate = productDetail.StartTime.Value.ToString("yyyy-MM-dd");
            //远程服务器是否返回404错误
            bool remote404 = false;
            //查询各个.OF基金在周报基金成立那天的累计单位净值，是单个数据
            Parallel.ForEach(list, (item, looup) =>
            {
                string url = baseUrl + $"codes={item}&startDate={_startDate}&endDate={_startDate}";
                string itemJson = string.Empty;
                try
                {
                    itemJson = HttpHelper.WebClientGet(url);
                    dynamic objData = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(itemJson);
                    if (Convert.ToInt32(objData.Head.Status.Value) == 1)
                    {
                        string jsonResult = Newtonsoft.Json.JsonConvert.SerializeObject(objData.Result);
                        List<FundQuote> tempList = Newtonsoft.Json.JsonConvert.DeserializeObject<List<FundQuote>>(jsonResult);
                        Parallel.ForEach(tempList, _FundQuote =>
                        {
                            double netvalue = _FundQuote.NetAssetValue.HasValue ? _FundQuote.NetAssetValue.Value : 0;
                            dict.TryAdd(_FundQuote.DisplayCode, netvalue);
                        });
                    }
                }
                catch (Exception ex)//ex.Response.StatusCode
                {
                    if (ex.Message.Contains("404"))
                    {
                        remote404 = true;
#if DEBUG
                        MessageHelper.LogErrorInfo("查询.OF基金在周报基金成立日期时的累积净值异常，源数据服务返回404错误");
#endif
                        //sameAvgNetValErrorMsg = "没有获取到.OF基金在周报基金成立日期时的累积净值";
                        looup.Stop();
                        return;
                    }
                    string code1 = item.Split(',')[0];
                    string code2 = item.Split(',')[1];
                    dict.TryAdd(code1, 0);
                    dict.TryAdd(code2, 0);
                    MessageHelper.LogErrorInfo("查询.OF基金在周报基金成立日期时的累积净值异常", ex);
                }
            });
            if (remote404)
            {
                return newList;
            }
            ////查找000844.OF基金的净值集合
            //var _chaz844 = dict.AsParallel().Where(w => w.Key.Equals("000844.OF")).ToList();
            //int km = 5566;

            //获取日期范围内的基金报价列表数据，为了获取日期的累计单位净值
            var taskParallel = Parallel.ForEach(list, (item, lookUp, index) =>
             {
                 //Stopwatch st2 = new Stopwatch();
                 //st2.Start();
                 string url = baseUrl + $"codes={item}&startDate={startDate}&endDate={endDate}";
                 string itemJson = HttpHelper.WebClientGet(url);
                 dynamic objData = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(itemJson);
                 if (Convert.ToInt32(objData.Head.Status.Value) == 1)
                 {
                     string jsonResult = Newtonsoft.Json.JsonConvert.SerializeObject(objData.Result);
                     List<FundQuote> tempList = Newtonsoft.Json.JsonConvert.DeserializeObject<List<FundQuote>>(jsonResult);
                     if (tempList != null && tempList.Count > 0)
                     {
                         Parallel.ForEach(tempList, itemNbum =>
                         {
                             if (itemNbum == null)
                             {
                                 tempList.Remove(itemNbum);
                             }
                         });
                         //tempList.RemoveAll(w => w == null);
                         fundQuoteList.AddRange(tempList);
                     }
                 }
#if DEBUG
                 else
                 {
                     MessageHelper.LogErrorInfo("基金报价列表异常" + itemJson);
                 }
#endif
                 //st2.Stop();
                 //MessageHelper.LogInfo(index + ":执行时间" + st2.ElapsedMilliseconds + "，参数" + item);
             });
            //检查是否已完成循环
            while (!taskParallel.IsCompleted) { Thread.SpinWait(2); }
            //taskParallel.IsCompleted
            //st.Stop();
            //MessageHelper.LogInfo("基金报价列表获取耗时" + st.ElapsedMilliseconds + "，列表个数" + fundQuoteList.Count + System.Environment.NewLine);

            //计算基金当天累计收益率
            //同类均值累计收益率成立日期为0 %
            //基金当天的累计净值/基金在那天（周报基金成立日）的累计净值-1=基金当天累计收益率
            //计算列表里面的日期那天的，基金当天累计收益率
            ConcurrentBag<FundQuote> dayIncomeRateList = new ConcurrentBag<FundQuote>();
            Parallel.ForEach(fundQuoteList, item =>
            {
                if (item != null)
                {
                    double netval = dict[item.DisplayCode];//.OF基金在周报基金成立日那天的累计单位净值
                    double comeRate = 0;
                    if (netval > 0)
                    {
                        comeRate = item.NetAssetValue.Value / netval - 1;//基金当天累计收益率
                    }
                    //此处AccumulatedNetAssetValue直接赋值为：当天的累计收益率了
                    dayIncomeRateList.Add(new FundQuote() { DisplayCode = item.DisplayCode, ValueDate = item.ValueDate, NetAssetValue = comeRate });
                }
            });
            //获取日期列表
            dateList = dayIncomeRateList.AsParallel().Select(w => w.ValueDate).Distinct().ToList();
            //循环日期，计算所有.OF基金在同一天的累计收益率平均收益，同时返回同类平均净值
            Parallel.ForEach(dateList, item =>
            {
                //计算平均收益率
                double? avgRate = dayIncomeRateList.AsParallel().Where(w => w.ValueDate == item).Average(w => w.NetAssetValue);
                double netvalue = Convert.ToDouble(avgRate) + 1;
                netvalue = Math.Round(netvalue, 9);
                //同类均值净值走势
                netvalueDict.TryAdd(DateHelpter.Stamp(item.Value) * 1000, netvalue);
            });
            newList = netvalueDict.ToList();
            //下面处理特殊情况，当某个周五没得净值时，取其周五前最近的一天的净值填充这周五净值
            //找出周五的记录
            List<KeyValuePair<long, double>> fridayList = netvalueDict.AsParallel().Where(w => DateHelpter.StampToDateTime(w.Key / 1000).DayOfWeek == DayOfWeek.Friday).OrderBy(w => w.Key).ToList();
            if (fridayList != null && fridayList.Count > 0)
            {
                //判断两个记录之间的日期天数差
                KeyValuePair<long, double> lastObj = fridayList[0];
                for (int i = 1; i < fridayList.Count; i++)
                {
                    var item = fridayList[i];
                    int cha = (int)(item.Key / 1000 - lastObj.Key / 1000) / (3600 * 24);//转换为差多少天
                    if (cha > 7)
                    {
                        //表示此范围有周五没有数据，找出此天，然后填充值
                        DateTime addFridayItem = DateHelpter.StampToDateTime(lastObj.Key / 1000).AddDays(7);
                        long date = DateHelpter.Stamp(addFridayItem) * 1000;
                        //查找前最近一天的净值
                        var _sameSearchList = newList.AsParallel().Where(w => w.Key < date).OrderBy(w => w.Key);
                        if (_sameSearchList != null && _sameSearchList.Count() > 0)
                        {
                            double netVal = _sameSearchList.Last().Value;
                            newList.Add(new KeyValuePair<long, double>(date, netVal));
                        }
                    }
                    lastObj = item;
                }
            }
            newList = newList.OrderBy(w => w.Key).ToList();
            //缓存数据      
            _cache.Set(cacheKey, newList, DateTimeOffset.Now.AddSeconds(SysCoinfgData.MemoryCacheLiveTime));
            //}
#if DEBUG
            StringBuilder sbBuilder = new StringBuilder();
            foreach (var item in newList)
            {
                sbBuilder.AppendLine(item.Key + "," + item.Value);
            }
            MessageHelper.LogInfo("同类均值填补处理后的净值：" + System.Environment.NewLine + sbBuilder.ToString());
#endif
            return newList;
        }

        /// <summary>
        /// 计算基准的单位净值走势
        /// </summary>
        /// <param name="token"></param>
        /// <param name="code"></param>
        /// <param name="startDate"></param>
        /// <param name="endDate"></param>
        /// <returns></returns>
        public List<double[]> UnitNetValueBenchmark(string token, string code, string startDate, string endDate)
        {
            string cacheKey = $"UnitNetValueBenchmark{code}{startDate}{endDate}";
            object cacheObj = _cache.Get(cacheKey);
            if (cacheObj != null)
            {
                return cacheObj as List<double[]>;
            }
            //获取指定code的行情         
            List<CodeQuotation> list = CodeQuotationCache(token, code, startDate, endDate);
            ConcurrentBag<double[]> unitNetValues = new ConcurrentBag<double[]>();
            if (list == null)
            {
                return unitNetValues.ToList<double[]>();
            }
            var firstObj = list.First();
            Parallel.ForEach(list, item =>
            {
                //基准单位净值 = 当前日收盘点数 / 开始日收盘点数
                double BenchmarkNnitNetValue = item.Close / firstObj.Close;
                double currentValue = Math.Round(BenchmarkNnitNetValue, 9);
                double date = DateHelpter.Stamp(item.Date.Date) * 1000; //item.Date.ToString("yyyy-MM-dd");
                unitNetValues.Add(new double[] { date, currentValue });
            });
            List<double[]> listZhuan = unitNetValues.OrderBy(w => w[0]).ToList();
            //下面处理特殊情况，当某个周五没得净值时，取其周五前最近的一天的净值填充这周五净值
            //找出周五的记录
            List<double[]> fridayList = listZhuan.AsParallel().Where(w => DateHelpter.StampToDateTime((long)w[0] / 1000).DayOfWeek == DayOfWeek.Friday).OrderBy(w => w[0]).ToList();
            if (fridayList != null && fridayList.Count > 0)
            {
                //判断两个记录之间的日期天数差
                double[] lastObj = fridayList[0];
                for (int i = 1; i < fridayList.Count; i++)
                {
                    var item = fridayList[i];
                    int cha = (int)(item[0] / 1000 - lastObj[0] / 1000) / (3600 * 24);//转换为差多少天
                    if (cha > 7)
                    {
                        //表示此范围有周五没有数据，找出此天，然后填充值
                        DateTime addFridayItem = DateHelpter.StampToDateTime((long)lastObj[0] / 1000).AddDays(7);
                        double date = DateHelpter.Stamp(addFridayItem) * 1000;
                        //查找前最近一天的净值
                        var benkSearchList = listZhuan.AsParallel().Where(w => w[0] < date).OrderBy(w => w[0]);
                        if (benkSearchList != null && benkSearchList.Count() > 0)
                        {
                            double netVal = benkSearchList.Last()[1];
                            listZhuan.Add(new double[] { date, netVal });
                        }
                    }
                    lastObj = item;
                }
            }
            listZhuan = listZhuan.OrderBy(w => w[0]).ToList();
            //缓存数据      
            _cache.Set(cacheKey, listZhuan, DateTimeOffset.Now.AddSeconds(SysCoinfgData.MemoryCacheLiveTime));
#if DEBUG
            StringBuilder sbBuilder = new StringBuilder();
            foreach (var item in listZhuan)
            {
                sbBuilder.AppendLine(item[0] + "," + item[1]);
            }
            MessageHelper.LogInfo("沪深300填补处理后的净值：" + System.Environment.NewLine + sbBuilder.ToString());
#endif
            return listZhuan;
        }

        /// <summary>
        /// 今年业绩（周）40
        /// </summary>
        /// <param name="token"></param>
        /// <param name="parames"></param>
        /// <returns></returns>
        public async Task<BackResult<object>> ThisYearPerformanceWeek(string token, TargetParames parames)
        {
            string cacheKey = $"ThisYearPerformanceWeek{parames.AnalysisId}{parames.StartDate}{parames.EndDate}";
            object cacheObj = _cache.Get(cacheKey);
            if (cacheObj != null)
            {
                return new BackResult<object>() { Data = cacheObj };
            }
            //计算同类均值的单位净值走势
            var task_tonglei = Task.Factory.StartNew(() =>
            {
                return SameAvgNetVal(token, parames.ProductId, parames.StartDate, parames.EndDate);
            }, TaskCreationOptions.LongRunning);

            string json = AnalysisCalculateCache(token, parames.AnalysisId, parames.StartDate, parames.EndDate);
            dynamic jsonObject = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(json);
            if (Convert.ToInt32(jsonObject.Head.Code.Value) >= 400)
            {
                return new BackResult<object>() { Success = false, Msg = "来自源数据消息：" + jsonObject.Head.Message };
            }
            string jsonPerformanceDetail = Newtonsoft.Json.JsonConvert.SerializeObject(jsonObject.Result.Performance.PerformanceDetail);
            double max_jizhun = 0, //基准最优收益率
                avg_jizhun = 0,             //基准平均收益率
                min_jizhun = 0,              //基准最大回撤率（最低收益率）
                max_fund = 0,               //基金最优收益率
                avg_fund = 0,                //基金平均收益率
                min_fund = 0;               //基金最大回撤率（最低收益率）
            List<double[]> fundList = null;  //基金净值集合
            List<double[]> jizhunlist = null;//基准净值集合
            var task1 = Task.Run(() =>
              {
                  //----------计算基准收益率-------
                  //基准单位净值走势
                  jizhunlist = UnitNetValueBenchmark(token, "000300.SH", parames.StartDate, parames.EndDate);
                  //周收益率集合
                  List<double[]> benk_weekReturn = new List<double[]>();
                  //第一天收益率为0
                  benk_weekReturn.Add(new double[] { jizhunlist.First()[0], 0 });
                  //选出每周五的单元
                  List<double[]> benk_fridayList = jizhunlist.AsParallel().Where(w => DateHelpter.StampToDateTime((long)w[0] / 1000).DayOfWeek == DayOfWeek.Friday).OrderBy(w => w[0]).ToList();
                  double benk_lastNetVal = 1;//最大开始的单位净值为1
                  if (benk_fridayList != null && benk_fridayList.Count > 0)
                  {
                      //计算每周五收益率
                      foreach (var item in benk_fridayList)
                      {
                          double weekReturnOne = item[1] / benk_lastNetVal - 1;
                          benk_weekReturn.Add(new double[] { item[0], weekReturnOne });
                          benk_lastNetVal = item[1];
                      }
                      //判断净值集合中，最后一条记录日期是否大于每周五集合最后一条日期，如果大于，则计算最近日期的收益率
                      int chaDays = (int)(jizhunlist.Last()[0] / 1000 - benk_fridayList.Last()[0] / 1000) / (3600 * 24);
                      if (chaDays > 1)
                      {
                          double benk_lastReturn = jizhunlist.Last()[1] / benk_fridayList.Last()[1] - 1;
                          benk_weekReturn.Add(new double[] { jizhunlist.Last()[0], benk_lastReturn });
                      }
                      //基准周收益率中的最优收益率
                      max_jizhun = benk_weekReturn.AsParallel().Max(w => w[1]);
                      avg_jizhun = benk_weekReturn.AsParallel().Average(w => w[1]);
                      min_jizhun = benk_weekReturn.AsParallel().Min(w => w[1]);
                  }
                  //-----基金单位净值走势------
                  fundList = FundsNetValues(token, parames.AnalysisId, parames.StartDate, parames.EndDate);
                  //--------计算周收益率-------
                  //周收益率集合
                  List<double[]> fund_weekReturn = new List<double[]>();
                  //第一天收益率为0
                  fund_weekReturn.Add(new double[] { fundList.First()[0], 0 });
                  //选出每周五的单元
                  List<double[]> fund_fridayList = fundList.AsParallel().Where(w => DateHelpter.StampToDateTime((long)w[0] / 1000).DayOfWeek == DayOfWeek.Friday).OrderBy(w => w[0]).ToList();
                  if (fund_fridayList != null && fund_fridayList.Count > 0)
                  {
                      //最大开始的单位净值为1
                      double fund_lastNetVal = 1;
                      //计算每周五收益率
                      foreach (var item in fund_fridayList)
                      {
                          double weekReturnOne = item[1] / fund_lastNetVal - 1;
                          fund_weekReturn.Add(new double[] { item[0], weekReturnOne });
                          fund_lastNetVal = item[1];
                      }
                      //判断净值集合中，最后一条记录日期是否大于每周五集合最后一条日期，如果大于，则计算最近日期的收益率
                      int fund_chaDays = (int)(fundList.Last()[0] / 1000 - fund_fridayList.Last()[0] / 1000) / (3600 * 24);
                      if (fund_chaDays > 1)
                      {
                          double fund_lastReturn = fundList.Last()[1] / fund_fridayList.Last()[1] - 1;
                          fund_weekReturn.Add(new double[] { fundList.Last()[0], fund_lastReturn });
                      }
                      //基金周收益率中的最优收益率
                      max_fund = fund_weekReturn.AsParallel().Max(w => w[1]);
                      avg_fund = fund_weekReturn.AsParallel().Average(w => w[1]);
                      min_fund = fund_weekReturn.AsParallel().Min(w => w[1]);
                  }
              });

            await task1;
            List<object> arr = new List<object>();
            //基金今年以来收益率
            DateTime lastDate = DateHelpter.StampToDateTime((long)fundList.Last()[0] / 1000);
            double thisYearFirstNetVal = fundList.AsParallel().Where(w => DateHelpter.StampToDateTime((long)w[0] / 1000).Year == lastDate.Year).OrderBy(w => w[0]).First()[1];
            double fundThisYearReturn = fundList.Last()[1] / thisYearFirstNetVal - 1;
            //基准今年以来收益率
            DateTime benk_lastDate = DateHelpter.StampToDateTime((long)jizhunlist.Last()[0] / 1000);
            double benk_thisYearFirstNetVal = jizhunlist.AsParallel().Where(w => DateHelpter.StampToDateTime((long)w[0] / 1000).Year == benk_lastDate.Year).OrderBy(w => w[0]).First()[1];
            double benchMarketThisYearReturn = jizhunlist.Last()[1] / benk_thisYearFirstNetVal - 1;

            //------计算同类均值收益率-----
            double same_max = 0,
            //平均收益率
            same_avg = 0,
            //最大回撤收益率
            same_min = 0,
            //今年以来收益率
            same_ThisYearReturn = 0;
            List<KeyValuePair<long, double>> netvalueDict = await task_tonglei;
            //先计算每周收益率
            //周收益率集合
            List<double[]> same_weekReturn = new List<double[]>();
            if (netvalueDict != null && netvalueDict.Count > 0)
            {
                //第一天收益率为0
                same_weekReturn.Add(new double[] { netvalueDict.First().Key, 0 });
                //选出每周五的单元
                List<KeyValuePair<long, double>> same_fridayList = netvalueDict.AsParallel().Where(w => DateHelpter.StampToDateTime(w.Key / 1000).DayOfWeek == DayOfWeek.Friday).OrderBy(w => w.Key).ToList();
                if (same_fridayList.Count > 0)
                {
                    //最大开始的单位净值为1
                    double lastNetVal = 1;
                    //计算每周五收益率
                    foreach (var item in same_fridayList)
                    {
                        double weekReturnOne = item.Value / lastNetVal - 1;
                        same_weekReturn.Add(new double[] { item.Key, weekReturnOne });
                        lastNetVal = item.Value;
                    }
                    //检查净值最有一天是否在每周五集合最后一天只前
                    int same_chaDays = (int)(netvalueDict.Last().Key / 1000 - same_fridayList.Last().Key / 1000) / (3600 * 24);
                    if (same_chaDays > 1)
                    {
                        double same_lastReturn = netvalueDict.Last().Value / same_fridayList.Last().Value - 1;
                        same_weekReturn.Add(new double[] { netvalueDict.Last().Key, same_lastReturn });
                    }
                    same_max = same_weekReturn.AsParallel().Max(w => w[1]);
                    same_avg = same_weekReturn.AsParallel().Average(w => w[1]);
                    same_min = same_weekReturn.AsParallel().Min(w => w[1]);
                }
                //计算今年以来
                List<KeyValuePair<long, double>> all_sameNetVal = netvalueDict.OrderBy(w => w.Key).ToList();
                DateTime same_lastDate = DateHelpter.StampToDateTime(all_sameNetVal.Last().Key / 1000);
                double same_thisYearFirstNetVal = all_sameNetVal.Where(w => DateHelpter.StampToDateTime(w.Key / 1000).Year == same_lastDate.Year).First().Value;
                same_ThisYearReturn = all_sameNetVal.Last().Value / same_thisYearFirstNetVal - 1;
            }

            List<object> itemObj = new List<object>();
            itemObj.Add(new { Des = "名称", CellVal = "基金" });
            itemObj.Add(new { Des = "最优收益", CellVal = max_fund });
            itemObj.Add(new { Des = "最大回撤", CellVal = min_fund });
            itemObj.Add(new { Des = "平均收益", CellVal = avg_fund });
            itemObj.Add(new { Des = "今年以来收益", CellVal = fundThisYearReturn });
            arr.Add(itemObj);
            List<object> itemObj3 = new List<object>();
            itemObj3.Add(new { Des = "名称", CellVal = "同类均值" });
            itemObj3.Add(new { Des = "最优收益", CellVal = same_max });
            itemObj3.Add(new { Des = "最大回撤", CellVal = same_min });
            itemObj3.Add(new { Des = "平均收益", CellVal = same_avg });
            itemObj3.Add(new { Des = "今年以来收益", CellVal = same_ThisYearReturn });
            arr.Add(itemObj3);
            List<object> itemObj2 = new List<object>();
            itemObj2.Add(new { Des = "名称", CellVal = "沪深300" });
            itemObj2.Add(new { Des = "最优收益", CellVal = max_jizhun });
            itemObj2.Add(new { Des = "最大回撤", CellVal = min_jizhun });
            itemObj2.Add(new { Des = "平均收益", CellVal = avg_jizhun });
            itemObj2.Add(new { Des = "今年以来收益", CellVal = benchMarketThisYearReturn });
            arr.Add(itemObj2);
            //缓存数据      
            _cache.Set(cacheKey, arr, DateTimeOffset.Now.AddSeconds(SysCoinfgData.MemoryCacheLiveTime));
            return new BackResult<object>() { Data = arr };
        }

        /// <summary>
        /// 本年度周收益率，有缓存  50      
        /// </summary>
        /// <param name="token"></param>
        /// <param name="parames"></param>
        /// <returns></returns>
        public async Task<BackResult<object>> ThisYearWeekIncomeRate(string token, TargetParames parames)
        {
            string cacheKey = $"ThisYearWeekIncomeRate{parames.AnalysisId}{parames.StartDate}{parames.EndDate}";
            object cacheObj = _cache.Get(cacheKey);
            if (cacheObj != null)
            {
                return new BackResult<object>() { Data = cacheObj };
            }
            //基金单位净值走势
            var task_fundNetVal = Task.Factory.StartNew(() =>
            {
                return FundsNetValues(token, parames.AnalysisId, parames.StartDate, parames.EndDate);
            }, TaskCreationOptions.LongRunning);
            //计算同类均值的单位净值走势
            var task_tonglei = Task.Factory.StartNew(() =>
            {
                return SameAvgNetVal(token, parames.ProductId, parames.StartDate, parames.EndDate);
            }, TaskCreationOptions.LongRunning);
            //基准单位净值走势，要自己算，这里只算沪深300
            var task1 = Task.Factory.StartNew(() =>
            {
                return UnitNetValueBenchmark(token, "000300.SH", parames.StartDate, parames.EndDate);
            }, TaskCreationOptions.LongRunning);

            //基金单位净值走势         
            List<double[]> fundList = await task_fundNetVal;
            //计算周收益率
            //本周收益率
            //本周五的净值 / 上周五的净值 - 1            
            //如果截止日不是星期五，则
            //截止日的净值 / 上周五的净值 - 1           
            //--------计算周收益率-------
            //装计算好的基金周收益率
            List<double[]> fund_weekReturn = new List<double[]>();
            if (fundList.Count > 0)
            {
                //第一天收益率为0
                fund_weekReturn.Add(new double[] { fundList.First()[0], 0 });
            }
            //选出每周五的单元
            List<double[]> fund_fridayList = fundList.AsParallel().Where(w => DateHelpter.StampToDateTime((long)w[0] / 1000).DayOfWeek == DayOfWeek.Friday).OrderBy(w => w[0]).ToList();
            if (fund_fridayList.Count > 0)
            {
                double fund_lastNetVal = 1;
                //计算每周五收益率
                foreach (var item in fund_fridayList)
                {
                    double weekReturnOne = item[1] / fund_lastNetVal - 1;
                    fund_weekReturn.Add(new double[] { item[0], weekReturnOne });
                    fund_lastNetVal = item[1];
                }
                //判断净值集合中，最后一条记录日期是否大于每周五集合最后一条日期，如果大于，则计算最近日期的收益率
                int fund_chaDays = (int)(fundList.Last()[0] / 1000 - fund_fridayList.Last()[0] / 1000) / (3600 * 24);
                if (fund_chaDays > 1)
                {
                    double fund_lastReturn = fundList.Last()[1] / fund_fridayList.Last()[1] - 1;
                    fund_weekReturn.Add(new double[] { fundList.Last()[0], fund_lastReturn });
                }
            }
            //时间轴            
            List<double> fund_xData = fund_weekReturn.AsParallel().Select(w => w[0]).OrderBy(w => w).ToList();
            List<double> fund_yData = fund_weekReturn.Select(w => w[1]).ToList();

            //计算基准(沪深300)的周收益率 
            var benchmarkUnitNetValues = await task1;
            //周收益率集合
            List<double[]> benk_weekReturn = new List<double[]>();
            if (benchmarkUnitNetValues.Count > 0)
            {
                //第一天收益率为0
                benk_weekReturn.Add(new double[] { benchmarkUnitNetValues.First()[0], 0 });
            }
            //选出每周五的单元
            List<double[]> benk_fridayList = benchmarkUnitNetValues.AsParallel().Where(w => DateHelpter.StampToDateTime((long)w[0] / 1000).DayOfWeek == DayOfWeek.Friday).OrderBy(w => w[0]).ToList();
            if (benk_fridayList.Count > 0)
            {
                double benk_lastNetVal = 1;
                foreach (var item in benk_fridayList)
                {
                    double weekReturnOne = item[1] / benk_lastNetVal - 1;
                    benk_weekReturn.Add(new double[] { item[0], weekReturnOne });
                    benk_lastNetVal = item[1];
                }
                //判断净值集合中，最后一条记录日期是否大于每周五集合最后一条日期，如果大于，则计算最近日期的收益率
                int chaDays = (int)(benchmarkUnitNetValues.Last()[0] / 1000 - benk_fridayList.Last()[0] / 1000) / (3600 * 24);
                if (chaDays > 1)
                {
                    double benk_lastReturn = benchmarkUnitNetValues.Last()[1] / benk_fridayList.Last()[1] - 1;
                    benk_weekReturn.Add(new double[] { benchmarkUnitNetValues.Last()[0], benk_lastReturn });
                }
            }
            List<double> benk_xTime = benk_weekReturn.Select(w => w[0]).ToList();
            List<double> benkWeekRate = benk_weekReturn.Select(w => w[1]).ToList();

            //得到同类均值净值走势
            List<KeyValuePair<long, double>> sameAvgNetVal = await task_tonglei;
            //装周收益率
            List<double[]> same_weekReturn = new List<double[]>();
            if (sameAvgNetVal.Count > 0)
            {
                //第一天收益率为0
                same_weekReturn.Add(new double[] { sameAvgNetVal.First().Key, 0 });
            }
            //选出每周五的单元
            List<KeyValuePair<long, double>> same_fridayList = sameAvgNetVal.AsParallel().Where(w => DateHelpter.StampToDateTime(w.Key / 1000).DayOfWeek == DayOfWeek.Friday).OrderBy(w => w.Key).ToList();
            if (same_fridayList.Count > 0)
            {
                double lastNetVal = 1;//最大开始的单位净值为1
                                      //计算每周五收益率
                foreach (var item in same_fridayList)
                {
                    double weekReturnOne = item.Value / lastNetVal - 1;
                    same_weekReturn.Add(new double[] { item.Key, weekReturnOne });
                    lastNetVal = item.Value;
                }
                //检查净值最有一天是否在每周五集合最后一天只前
                int same_chaDays = (int)(sameAvgNetVal.Last().Key / 1000 - same_fridayList.Last().Key / 1000) / (3600 * 24);
                if (same_chaDays > 1)
                {
                    double same_lastReturn = sameAvgNetVal.Last().Value / same_fridayList.Last().Value - 1;
                    same_weekReturn.Add(new double[] { sameAvgNetVal.Last().Key, same_lastReturn });
                }
            }
            List<double> same_xTime = same_weekReturn.Select(w => w[0]).ToList();
            List<double> sameWeekRate = same_weekReturn.Select(w => w[1]).ToList();

            //fund_xData.RemoveAt(0);
            List<object> backList = new List<object>();
            //小数处理
            fund_yData = fund_yData.Select(w => Math.Round(w, 4)).ToList();
            benkWeekRate = benkWeekRate.Select(w => Math.Round(w, 4)).ToList();
            sameWeekRate = sameWeekRate.Select(w => Math.Round(w, 4)).ToList();
            //基金的周收益率             
            backList.Add(new
            {
                Name = "基金",
                xData = fund_xData,
                yData = fund_yData
            });
            //沪深300的周收益率             
            backList.Add(new
            {
                Name = "沪深300",
                xData = benk_xTime,
                yData = benkWeekRate
            });
            //同类均值的周收益率             
            backList.Add(new
            {
                Name = "同类均值",
                xData = same_xTime,
                yData = sameWeekRate
            });
            //缓存数据      
            _cache.Set(cacheKey, backList, DateTimeOffset.Now.AddSeconds(SysCoinfgData.MemoryCacheLiveTime));
            return new BackResult<object>() { Data = backList };
        }

        /// <summary>
        /// 持仓信息，资产配置70
        /// </summary>
        /// <param name="token"></param>
        /// <param name="parames"></param>
        /// <returns></returns>
        public async Task<BackResult<object>> AssetAllocation(string token, TargetParames parames)
        {
            string json = await Task.Factory.StartNew(() =>
            {
                return AnalysisCalculateCache(token, parames.AnalysisId, parames.StartDate, parames.EndDate);
            }, TaskCreationOptions.LongRunning);
            dynamic jsonObject = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(json);
            if (jsonObject.Result.AssetAllocation == null)
            {
                return new BackResult<object>() { Success = false, Msg = "此日期范围没有【持仓信息】数据", Data = new List<object>() };
            }
            string jsonAsset = Newtonsoft.Json.JsonConvert.SerializeObject(jsonObject.Result.AssetAllocation.LastAssetAllocation);
            List<AsstAll> list = Newtonsoft.Json.JsonConvert.DeserializeObject<List<AsstAll>>(jsonAsset);
            List<object> backData = new List<object>();
            foreach (var item in list)
            {
                List<object> row = new List<object>();
                row.Add(new { Des = "类别", CellVal = item.Name });
                row.Add(new { Des = "占比", CellVal = item.AssetRatio });
                row.Add(new { Des = "金额(万)", CellVal = item.Amount });
                backData.Add(row);
            }
            //截止日资产配置 
            return new BackResult<object>() { Data = backData };
        }

        /// <summary>
        /// 行业配置80
        /// </summary>
        /// <param name="token"></param>
        /// <param name="parames"></param>
        /// <returns></returns>
        public async Task<BackResult<object>> IndustryStructure(string token, TargetParames parames)
        {
            var json = await Task.Factory.StartNew(() =>
            {
                return AnalysisCalculateCache(token, parames.AnalysisId, parames.StartDate, parames.EndDate);
            }, TaskCreationOptions.LongRunning);
            dynamic jsonObject = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(json);
            if (Convert.ToInt32(jsonObject.Head.Code.Value) > 400)
            {
                return new BackResult<object>() { Success = false, Msg = "来自源数据消息：" + jsonObject.Head.Message };
            }
            if (jsonObject.Result.StockIndustryWeightTrend == null)
            {
                return new BackResult<object>() { Msg = "此日期范围没有【行业配置】数据", Data = new List<object>() };
            }
            ConcurrentBag<object> industryWeightArr = new ConcurrentBag<object>();
            string weightTrendk_json = Newtonsoft.Json.JsonConvert.SerializeObject(jsonObject.Result.StockIndustryWeightTrend.IndustryWeights);
            List<IndustryWeights> industryWeights = Newtonsoft.Json.JsonConvert.DeserializeObject<List<IndustryWeights>>(weightTrendk_json);
            //基金市值
            double fundMaketValue = 0;
            if (jsonObject.Result.MarketValueAllocation != null)
            {
                fundMaketValue = Convert.ToDouble(jsonObject.Result.MarketValueAllocation.LastMarketValue.LastHigh.Value);
            }
            else
            {
                //计算总市值，如果上面的没得值，从基金规模获取
                string json_fundScaleData = Newtonsoft.Json.JsonConvert.SerializeObject(jsonObject.Result.FundScaleChange.FundScaleData);
                List<double[]> fundScaleData = Newtonsoft.Json.JsonConvert.DeserializeObject<List<double[]>>(json_fundScaleData);
                fundMaketValue = fundScaleData.AsParallel().Last()[1];
            }
            //double fundMaketValue = Convert.ToDouble(jsonObject.Result.MarketValueAllocation.LastMarketValue.LastHigh.Value);
            //var log = Task.Run(() =>
            //{
            //    MessageHelper.LogInfo("基金市值" + fundMaketValue);
            //});
            Parallel.ForEach(industryWeights, item =>
            {
                double shizhi = 0;
                double zhanbi = 0;
                if (item != null && item.Data != null && item.Data.Count > 0)
                {
                    zhanbi = item.Data.AsParallel().Last()[1];
                    shizhi = zhanbi * fundMaketValue;
                }
                List<object> row = new List<object>();
                row.Add(new { Des = "行业名称", CellVal = item.Name });
                row.Add(new { Des = "占比", CellVal = zhanbi });
                row.Add(new { Des = "市值(万)", CellVal = shizhi });
                industryWeightArr.Add(row);
            });
            return new BackResult<object>() { Data = industryWeightArr };
        }

        /// <summary>
        /// 重仓证券90
        /// </summary>
        /// <param name="token"></param>
        /// <param name="parames"></param>
        /// <returns></returns>
        public async Task<BackResult<object>> HeavySecuritie(string token, TargetParames parames)
        {
            var json = await Task.Factory.StartNew(() =>
            {
                return AnalysisCalculateCache(token, parames.AnalysisId, parames.StartDate, parames.EndDate);
            }, TaskCreationOptions.LongRunning);
            dynamic jsonObject = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(json);
            if (Convert.ToInt32(jsonObject.Head.Code.Value) > 400)
            {
                return new BackResult<object>() { Success = false, Msg = "来自源数据消息：" + jsonObject.Head.Message };
            }
            if (jsonObject.Result.ConcentrationOnStocks == null)
            {
                return new BackResult<object>() { Msg = "此日期范围没有【重仓证券】数据", Data = new List<object>() };
            }
            string jsonStocks = Newtonsoft.Json.JsonConvert.SerializeObject(jsonObject.Result.ConcentrationOnStocks.StockConcentration);
            List<Stocks> list = Newtonsoft.Json.JsonConvert.DeserializeObject<List<Stocks>>(jsonStocks);
            List<object> backData = new List<object>();
            foreach (var item in list)
            {
                double floatRate = 0;
                if (item.Cost > 0)
                {
                    floatRate = item.MarketValue / item.Cost - 1;
                }
                List<object> row = new List<object>();
                row.Add(new { Des = "代码", CellVal = item.Code });
                row.Add(new { Des = "简称", CellVal = item.Name });
                row.Add(new { Des = "占比净值", CellVal = item.NetValueRatio });
                row.Add(new { Des = "浮动收益率", CellVal = floatRate });
                backData.Add(row);
            }
            return new BackResult<object>() { Data = backData };
        }

        /// <summary>
        /// 获取基准的市场行情数据（缓存）
        /// </summary>
        /// <param name="token"></param>
        /// <param name="code"></param>
        /// <param name="startDate"></param>
        /// <param name="endDate"></param>
        /// <returns></returns>
        public List<CodeQuotation> CodeQuotationCache(string token, string code, string startDate, string endDate)
        {
            string cacheKey = $"CodeQuotationCache{code}{startDate}{endDate}";
            object cacheObj = _cache.Get(cacheKey);
            if (cacheObj != null)
            {
                return cacheObj as List<CodeQuotation>;
            }
            //lock (_lockObject)
            //{
            //获取指定code的行情
            string url = SysCoinfgData.ApiBaesURL + "/api/UserReport/CodeQuotation";
            var sendObj = new
            {
                Body = new
                {
                    Code = code,  //基准编码
                    StartTime = startDate,
                    EndTime = endDate
                }
            };
            string sendJson = Newtonsoft.Json.JsonConvert.SerializeObject(sendObj);
            string backJson = HttpHelper.WebClientPost(url, sendJson, token);

            dynamic jsonObj = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(backJson);
            if (Convert.ToInt32(jsonObj.Head.Code.Value) > 400)
            {
                throw new OutMsgException("来自源数据消息：" + jsonObj.Head.Message);
            }
            string dataJson = Newtonsoft.Json.JsonConvert.SerializeObject(jsonObj.Result);
            List<CodeQuotation> list = Newtonsoft.Json.JsonConvert.DeserializeObject<List<CodeQuotation>>(dataJson);
            //缓存数据      
            _cache.Set(cacheKey, list, DateTimeOffset.Now.AddSeconds(SysCoinfgData.MemoryCacheLiveTime));
            return list;
            //}
        }

        /// <summary>
        /// 获取业绩详细重算结果(沪深300)，缓存
        /// </summary>
        /// <param name="token"></param>
        /// <param name="analysisId"></param>
        /// <param name="startDate"></param>
        /// <param name="endDate"></param>
        /// <returns></returns>
        public string AnalysisCalculateCache(string token, int analysisId, string startDate, string endDate)
        {
            string json = string.Empty;
#if DEBUG
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
#endif
            lock (_lockObject)
            {
                string cacheKey = $"AnalysisCalculateCache{analysisId}{startDate}{endDate}";
                object cacheObj = _cache.Get(cacheKey);
                if (cacheObj != null)
                {
                    return Convert.ToString(cacheObj);
                }
#if DEBUG
                MessageHelper.LogInfo("AnalysisCalculateCache进入了查询");
#endif

                //调用业绩分析计算
                string url = SysCoinfgData.ApiBaesURL + "/api/PerformanceAnalysis/Calculate";
                var obj = new
                {
                    Body = new
                    {
                        AnalysisId = analysisId,//分析id
                        StartTime = startDate,
                        EndTime = endDate,
                        BenchmarkCode = "000300.SH", //基准，沪深300
                        PerformanceType = 3 // 分析类型，0交易记录，1资金交易记录，2净值类型，3故值类型，4净值持仓
                    }
                };
                json = HttpHelper.WebClientPost(url, Newtonsoft.Json.JsonConvert.SerializeObject(obj), token);
                dynamic jsonObject = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(json);
                if (Convert.ToInt32(jsonObject.Head.Code.Value) > 400)
                {
                    //不缓存数据，无意义数据
                    //doCache = false;
                    throw new OutMsgException("AnalysisCalculateCache来自源数据消息：" + jsonObject.Head.Message.Value);
                }
                //缓存数据      
                _cache.Set(cacheKey, json, DateTimeOffset.Now.AddSeconds(SysCoinfgData.MemoryCacheLiveTime));
            }
#if DEBUG
            stopwatch.Stop();
            MessageHelper.LogInfo("AnalysisCalculateCache重算结果执行耗时：" + stopwatch.ElapsedMilliseconds);
#endif
            return json;
        }

    }
}